home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 008a / perl40_2.zip / STR.C < prev    next >
C/C++ Source or Header  |  1991-11-28  |  35KB  |  1,638 lines

  1. /* $RCSfile: str.c,v $$Revision: 4.0.1.4 $$Date: 91/11/05 18:40:51 $
  2.  *
  3.  *    Copyright (c) 1991, Larry Wall
  4.  *
  5.  *    You may distribute under the terms of either the GNU General Public
  6.  *    License or the Artistic License, as specified in the README file.
  7.  *
  8.  * $Log:    str.c,v $
  9.  * Revision 4.0.1.4  91/11/05  18:40:51  lwall
  10.  * patch11: $foo .= <BAR> could overrun malloced memory
  11.  * patch11: \$ didn't always make it through double-quoter to regexp routines
  12.  * patch11: prepared for ctype implementations that don't define isascii()
  13.  *
  14.  * Revision 4.0.1.3  91/06/10  01:27:54  lwall
  15.  * patch10: $) and $| incorrectly handled in run-time patterns
  16.  *
  17.  * Revision 4.0.1.2  91/06/07  11:58:13  lwall
  18.  * patch4: new copyright notice
  19.  * patch4: taint check on undefined string could cause core dump
  20.  *
  21.  * Revision 4.0.1.1  91/04/12  09:15:30  lwall
  22.  * patch1: fixed undefined environ problem
  23.  * patch1: substr($ENV{"PATH"},0,0) = "/foo:" didn't modify environment
  24.  * patch1: $foo .= <BAR> could cause core dump for certain lengths of $foo
  25.  *
  26.  * Revision 4.0  91/03/20  01:39:55  lwall
  27.  * 4.0 baseline.
  28.  *
  29.  */
  30.  
  31.  
  32. #include "EXTERN.h"
  33. #include "perl.h"
  34. #include "perly.h"
  35.  
  36.  
  37. #ifndef str_get
  38. char *
  39. str_get(str)
  40. STR *str;
  41. {
  42. #ifdef TAINT
  43.     tainted |= str->str_tainted;
  44. #endif
  45.     return str->str_pok ? str->str_ptr : str_2ptr(str);
  46. }
  47. #endif
  48.  
  49.  
  50. /* dlb ... guess we have a "crippled cc".
  51.  * dlb the following functions are usually macros.
  52.  */
  53. #ifndef str_true
  54. str_true(Str)
  55. STR *Str;
  56. {
  57.     if (Str->str_pok) {
  58.         if (*Str->str_ptr > '0' ||
  59.           Str->str_cur > 1 ||
  60.           (Str->str_cur && *Str->str_ptr != '0'))
  61.         return 1;
  62.         return 0;
  63.     }
  64.     if (Str->str_nok)
  65.         return (Str->str_u.str_nval != 0.0);
  66.     return 0;
  67. }
  68. #endif /* str_true */
  69.  
  70.  
  71. #ifndef str_gnum
  72. double str_gnum(Str)
  73. STR *Str;
  74. {
  75. #ifdef TAINT
  76.     tainted |= Str->str_tainted;
  77. #endif /* TAINT*/
  78.     if (Str->str_nok)
  79.         return Str->str_u.str_nval;
  80.     return str_2num(Str);
  81. }
  82. #endif /* str_gnum */
  83. /* dlb ... end of crutch */
  84.  
  85.  
  86. char *
  87. str_grow(str,newlen)
  88. register STR *str;
  89. #ifndef MSDOS
  90. register int newlen;
  91. #else
  92. unsigned long newlen;
  93. #endif
  94. {
  95.     register char *s = str->str_ptr;
  96.  
  97.  
  98. #ifdef MSDOS
  99.     if (newlen >= 0x10000) {
  100.     fprintf(stderr, "Allocation too large: %lx\n", newlen);
  101.     exit(1);
  102.     }
  103. #endif /* MSDOS */
  104.     if (str->str_state == SS_INCR) {        /* data before str_ptr? */
  105.     str->str_len += str->str_u.str_useful;
  106.     str->str_ptr -= str->str_u.str_useful;
  107.     str->str_u.str_useful = 0L;
  108.     bcopy(s, str->str_ptr, str->str_cur+1);
  109.     s = str->str_ptr;
  110.     str->str_state = SS_NORM;            /* normal again */
  111.     if (newlen > str->str_len)
  112.         newlen += 10 * (newlen - str->str_cur); /* avoid copy each time */
  113.     }
  114.     if (newlen > str->str_len) {        /* need more room? */
  115.         if (str->str_len)
  116.         Renew(s,newlen,char);
  117.         else
  118.         New(703,s,newlen,char);
  119.     str->str_ptr = s;
  120.         str->str_len = newlen;
  121.     }
  122.     return s;
  123. }
  124.  
  125.  
  126. str_numset(str,num)
  127. register STR *str;
  128. double num;
  129. {
  130.     if (str->str_pok) {
  131.     str->str_pok = 0;    /* invalidate pointer */
  132.     if (str->str_state == SS_INCR)
  133.         Str_Grow(str,0);
  134.     }
  135.     str->str_u.str_nval = num;
  136.     str->str_state = SS_NORM;
  137.     str->str_nok = 1;            /* validate number */
  138. #ifdef TAINT
  139.     str->str_tainted = tainted;
  140. #endif
  141. }
  142.  
  143.  
  144. char *
  145. str_2ptr(str)
  146. register STR *str;
  147. {
  148.     register char *s;
  149.     int olderrno;
  150.  
  151.  
  152.     if (!str)
  153.     return "";
  154.     if (str->str_nok) {
  155.     STR_GROW(str, 30);
  156.     s = str->str_ptr;
  157.     olderrno = errno;    /* some Xenix systems wipe out errno here */
  158. #if defined(scs) && defined(ns32000)
  159.     gcvt(str->str_u.str_nval,20,s);
  160. #else
  161. #ifdef apollo
  162.     if (str->str_u.str_nval == 0.0)
  163.         (void)strcpy(s,"0");
  164.     else
  165. #endif /*apollo*/
  166.     (void)sprintf(s,"%.20g",str->str_u.str_nval);
  167. #endif /*scs*/
  168.     errno = olderrno;
  169.     while (*s) s++;
  170. #ifdef hcx
  171.     if (s[-1] == '.')
  172.         s--;
  173. #endif
  174.     }
  175.     else {
  176.     if (str == &str_undef)
  177.         return No;
  178.     if (dowarn)
  179.         warn("Use of uninitialized variable");
  180.     STR_GROW(str, 30);
  181.     s = str->str_ptr;
  182.     }
  183.     *s = '\0';
  184.     str->str_cur = s - str->str_ptr;
  185.     str->str_pok = 1;
  186. #ifdef DEBUGGING
  187.     if (debug & 32)
  188.     fprintf(stderr,"0x%lx ptr(%s)\n",str,str->str_ptr);
  189. #endif
  190.     return str->str_ptr;
  191. }
  192.  
  193.  
  194. double
  195. str_2num(str)
  196. register STR *str;
  197. {
  198.     if (!str)
  199.     return 0.0;
  200.     if (str->str_state == SS_INCR)
  201.     Str_Grow(str,0);       /* just force copy down */
  202.     str->str_state = SS_NORM;
  203.     if (str->str_len && str->str_pok)
  204.     str->str_u.str_nval = atof(str->str_ptr);
  205.     else  {
  206.     if (str == &str_undef)
  207.         return 0.0;
  208.     if (dowarn)
  209.         warn("Use of uninitialized variable");
  210.     str->str_u.str_nval = 0.0;
  211.     }
  212.     str->str_nok = 1;
  213. #ifdef DEBUGGING
  214.     if (debug & 32)
  215.     fprintf(stderr,"0x%lx num(%g)\n",str,str->str_u.str_nval);
  216. #endif
  217.     return str->str_u.str_nval;
  218. }
  219.  
  220.  
  221. /* Note: str_sset() should not be called with a source string that needs
  222.  * be reused, since it may destroy the source string if it is marked
  223.  * as temporary.
  224.  */
  225.  
  226.  
  227. str_sset(dstr,sstr)
  228. STR *dstr;
  229. register STR *sstr;
  230. {
  231. #ifdef TAINT
  232.     if (sstr)
  233.     tainted |= sstr->str_tainted;
  234. #endif
  235.     if (sstr == dstr || dstr == &str_undef)
  236.     return;
  237.     if (!sstr)
  238.     dstr->str_pok = dstr->str_nok = 0;
  239.     else if (sstr->str_pok) {
  240.  
  241.  
  242.     /*
  243.      * Check to see if we can just swipe the string.  If so, it's a
  244.      * possible small lose on short strings, but a big win on long ones.
  245.      * It might even be a win on short strings if dstr->str_ptr
  246.      * has to be allocated and sstr->str_ptr has to be freed.
  247.      */
  248.  
  249.  
  250.     if (sstr->str_pok & SP_TEMP) {        /* slated for free anyway? */
  251.         if (dstr->str_ptr) {
  252.         if (dstr->str_state == SS_INCR)
  253.             dstr->str_ptr -= dstr->str_u.str_useful;
  254.         Safefree(dstr->str_ptr);
  255.         }
  256.         dstr->str_ptr = sstr->str_ptr;
  257.         dstr->str_len = sstr->str_len;
  258.         dstr->str_cur = sstr->str_cur;
  259.         dstr->str_state = sstr->str_state;
  260.         dstr->str_pok = sstr->str_pok & ~SP_TEMP;
  261. #ifdef TAINT
  262.         dstr->str_tainted = sstr->str_tainted;
  263. #endif
  264.         sstr->str_ptr = Nullch;
  265.         sstr->str_len = 0;
  266.         sstr->str_pok = 0;            /* wipe out any weird flags */
  267.         sstr->str_state = 0;        /* so sstr frees uneventfully */
  268.     }
  269.     else {                    /* have to copy actual string */
  270.         if (dstr->str_ptr) {
  271.         if (dstr->str_state == SS_INCR) {
  272.             Str_Grow(dstr,0);
  273.         }
  274.         }
  275.         str_nset(dstr,sstr->str_ptr,sstr->str_cur);
  276.     }
  277.     /*SUPPRESS 560*/
  278.     if (dstr->str_nok = sstr->str_nok)
  279.         dstr->str_u.str_nval = sstr->str_u.str_nval;
  280.     else {
  281. #ifdef STRUCTCOPY
  282.         dstr->str_u = sstr->str_u;
  283. #else
  284.         dstr->str_u.str_nval = sstr->str_u.str_nval;
  285. #endif
  286.         if (dstr->str_cur == sizeof(STBP)) {
  287.         char *tmps = dstr->str_ptr;
  288.  
  289.  
  290.         if (*tmps == 'S' && bcmp(tmps,"StB",4) == 0) {
  291.             if (!dstr->str_magic) {
  292.             dstr->str_magic = str_smake(sstr->str_magic);
  293.             dstr->str_magic->str_rare = 'X';
  294.             }
  295.         }
  296.         }
  297.     }
  298.     }
  299.     else if (sstr->str_nok)
  300.     str_numset(dstr,sstr->str_u.str_nval);
  301.     else {
  302.     if (dstr->str_state == SS_INCR)
  303.         Str_Grow(dstr,0);       /* just force copy down */
  304.  
  305.  
  306. #ifdef STRUCTCOPY
  307.     dstr->str_u = sstr->str_u;
  308. #else
  309.     dstr->str_u.str_nval = sstr->str_u.str_nval;
  310. #endif
  311.     dstr->str_pok = dstr->str_nok = 0;
  312.     }
  313. }
  314.  
  315.  
  316. str_nset(str,ptr,len)
  317. register STR *str;
  318. register char *ptr;
  319. register STRLEN len;
  320. {
  321.     if (str == &str_undef)
  322.     return;
  323.     STR_GROW(str, len + 1);
  324.     if (ptr)
  325.     (void)bcopy(ptr,str->str_ptr,len);
  326.     str->str_cur = len;
  327.     *(str->str_ptr+str->str_cur) = '\0';
  328.     str->str_nok = 0;        /* invalidate number */
  329.     str->str_pok = 1;        /* validate pointer */
  330. #ifdef TAINT
  331.     str->str_tainted = tainted;
  332. #endif
  333. }
  334.  
  335.  
  336. str_set(str,ptr)
  337. register STR *str;
  338. register char *ptr;
  339. {
  340.     register STRLEN len;
  341.  
  342.  
  343.     if (str == &str_undef)
  344.     return;
  345.     if (!ptr)
  346.     ptr = "";
  347.     len = strlen(ptr);
  348.     STR_GROW(str, len + 1);
  349.     (void)bcopy(ptr,str->str_ptr,len+1);
  350.     str->str_cur = len;
  351.     str->str_nok = 0;        /* invalidate number */
  352.     str->str_pok = 1;        /* validate pointer */
  353. #ifdef TAINT
  354.     str->str_tainted = tainted;
  355. #endif
  356. }
  357.  
  358.  
  359. str_chop(str,ptr)    /* like set but assuming ptr is in str */
  360. register STR *str;
  361. register char *ptr;
  362. {
  363.     register STRLEN delta;
  364.  
  365.  
  366.     if (!ptr || !(str->str_pok))
  367.     return;
  368.     delta = ptr - str->str_ptr;
  369.     str->str_len -= delta;
  370.     str->str_cur -= delta;
  371.     str->str_ptr += delta;
  372.     if (str->str_state == SS_INCR)
  373.     str->str_u.str_useful += delta;
  374.     else {
  375.     str->str_u.str_useful = delta;
  376.     str->str_state = SS_INCR;
  377.     }
  378.     str->str_nok = 0;        /* invalidate number */
  379.     str->str_pok = 1;        /* validate pointer (and unstudy str) */
  380. }
  381.  
  382.  
  383. str_ncat(str,ptr,len)
  384. register STR *str;
  385. register char *ptr;
  386. register STRLEN len;
  387. {
  388.     if (str == &str_undef)
  389.     return;
  390.     if (!(str->str_pok))
  391.     (void)str_2ptr(str);
  392.     STR_GROW(str, str->str_cur + len + 1);
  393.     (void)bcopy(ptr,str->str_ptr+str->str_cur,len);
  394.     str->str_cur += len;
  395.     *(str->str_ptr+str->str_cur) = '\0';
  396.     str->str_nok = 0;        /* invalidate number */
  397.     str->str_pok = 1;        /* validate pointer */
  398. #ifdef TAINT
  399.     str->str_tainted |= tainted;
  400. #endif
  401. }
  402.  
  403.  
  404. str_scat(dstr,sstr)
  405. STR *dstr;
  406. register STR *sstr;
  407. {
  408.     if (!sstr)
  409.     return;
  410. #ifdef TAINT
  411.     tainted |= sstr->str_tainted;
  412. #endif
  413.     if (!(sstr->str_pok))
  414.     (void)str_2ptr(sstr);
  415.     if (sstr)
  416.     str_ncat(dstr,sstr->str_ptr,sstr->str_cur);
  417. }
  418.  
  419.  
  420. str_cat(str,ptr)
  421. register STR *str;
  422. register char *ptr;
  423. {
  424.     register STRLEN len;
  425.  
  426.  
  427.     if (str == &str_undef)
  428.     return;
  429.     if (!ptr)
  430.     return;
  431.     if (!(str->str_pok))
  432.     (void)str_2ptr(str);
  433.     len = strlen(ptr);
  434.     STR_GROW(str, str->str_cur + len + 1);
  435.     (void)bcopy(ptr,str->str_ptr+str->str_cur,len+1);
  436.     str->str_cur += len;
  437.     str->str_nok = 0;        /* invalidate number */
  438.     str->str_pok = 1;        /* validate pointer */
  439. #ifdef TAINT
  440.     str->str_tainted |= tainted;
  441. #endif
  442. }
  443.  
  444.  
  445. char *
  446. str_append_till(str,from,fromend,delim,keeplist)
  447. register STR *str;
  448. register char *from;
  449. register char *fromend;
  450. register int delim;
  451. char *keeplist;
  452. {
  453.     register char *to;
  454.     register STRLEN len;
  455.  
  456.  
  457.     if (str == &str_undef)
  458.     return Nullch;
  459.     if (!from)
  460.     return Nullch;
  461.     len = fromend - from;
  462.     STR_GROW(str, str->str_cur + len + 1);
  463.     str->str_nok = 0;        /* invalidate number */
  464.     str->str_pok = 1;        /* validate pointer */
  465.     to = str->str_ptr+str->str_cur;
  466.     for (; from < fromend; from++,to++) {
  467.     if (*from == '\\' && from+1 < fromend && delim != '\\') {
  468.         if (!keeplist) {
  469.         if (from[1] == delim || from[1] == '\\')
  470.             from++;
  471.         else
  472.             *to++ = *from++;
  473.         }
  474.         else if (from[1] && index(keeplist,from[1]))
  475.         *to++ = *from++;
  476.         else
  477.         from++;
  478.     }
  479.     else if (*from == delim)
  480.         break;
  481.     *to = *from;
  482.     }
  483.     *to = '\0';
  484.     str->str_cur = to - str->str_ptr;
  485.     return from;
  486. }
  487.  
  488.  
  489. STR *
  490. #ifdef LEAKTEST
  491. str_new(x,len)
  492. int x;
  493. #else
  494. str_new(len)
  495. #endif
  496. STRLEN len;
  497. {
  498.     register STR *str;
  499.  
  500.     if (freestrroot) {
  501.     str = freestrroot;
  502.     freestrroot = str->str_magic;
  503.     str->str_magic = Nullstr;
  504.     str->str_state = SS_NORM;
  505.     }
  506.     else {
  507.     Newz(700+x,str,1,STR);
  508.     }
  509.     if (len)
  510.     STR_GROW(str, len + 1);
  511.     return str;
  512. }
  513.  
  514.  
  515. void
  516. str_magic(str, stab, how, name, namlen)
  517. register STR *str;
  518. STAB *stab;
  519. int how;
  520. char *name;
  521. STRLEN namlen;
  522. {
  523.     if (str == &str_undef || str->str_magic)
  524.     return;
  525.     str->str_magic = Str_new(75,namlen);
  526.     str = str->str_magic;
  527.     str->str_u.str_stab = stab;
  528.     str->str_rare = how;
  529.     if (name)
  530.     str_nset(str,name,namlen);
  531. }
  532.  
  533.  
  534. void
  535. str_insert(bigstr,offset,len,little,littlelen)
  536. STR *bigstr;
  537. STRLEN offset;
  538. STRLEN len;
  539. char *little;
  540. STRLEN littlelen;
  541. {
  542.     register char *big;
  543.     register char *mid;
  544.     register char *midend;
  545.     register char *bigend;
  546.     register int i;
  547.  
  548.  
  549.     if (bigstr == &str_undef)
  550.     return;
  551.     bigstr->str_nok = 0;
  552.     bigstr->str_pok = SP_VALID;    /* disable possible screamer */
  553.  
  554.  
  555.     i = littlelen - len;
  556.     if (i > 0) {            /* string might grow */
  557.     STR_GROW(bigstr, bigstr->str_cur + i + 1);
  558.     big = bigstr->str_ptr;
  559.     mid = big + offset + len;
  560.     midend = bigend = big + bigstr->str_cur;
  561.     bigend += i;
  562.     *bigend = '\0';
  563.     while (midend > mid)        /* shove everything down */
  564.         *--bigend = *--midend;
  565.     (void)bcopy(little,big+offset,littlelen);
  566.     bigstr->str_cur += i;
  567.     STABSET(bigstr);
  568.     return;
  569.     }
  570.     else if (i == 0) {
  571.     (void)bcopy(little,bigstr->str_ptr+offset,len);
  572.     STABSET(bigstr);
  573.     return;
  574.     }
  575.  
  576.  
  577.     big = bigstr->str_ptr;
  578.     mid = big + offset;
  579.     midend = mid + len;
  580.     bigend = big + bigstr->str_cur;
  581.  
  582.  
  583.     if (midend > bigend)
  584.     fatal("panic: str_insert");
  585.  
  586.  
  587.     if (mid - big > bigend - midend) {    /* faster to shorten from end */
  588.     if (littlelen) {
  589.         (void)bcopy(little, mid, littlelen);
  590.         mid += littlelen;
  591.     }
  592.     i = bigend - midend;
  593.     if (i > 0) {
  594.         (void)bcopy(midend, mid, i);
  595.         mid += i;
  596.     }
  597.     *mid = '\0';
  598.     bigstr->str_cur = mid - big;
  599.     }
  600.     /*SUPPRESS 560*/
  601.     else if (i = mid - big) {    /* faster from front */
  602.     midend -= littlelen;
  603.     mid = midend;
  604.     str_chop(bigstr,midend-i);
  605.     big += i;
  606.     while (i--)
  607.         *--midend = *--big;
  608.     if (littlelen)
  609.         (void)bcopy(little, mid, littlelen);
  610.     }
  611.     else if (littlelen) {
  612.     midend -= littlelen;
  613.     str_chop(bigstr,midend);
  614.     (void)bcopy(little,midend,littlelen);
  615.     }
  616.     else {
  617.     str_chop(bigstr,midend);
  618.     }
  619.     STABSET(bigstr);
  620. }
  621.  
  622.  
  623. /* make str point to what nstr did */
  624.  
  625.  
  626. void
  627. str_replace(str,nstr)
  628. register STR *str;
  629. register STR *nstr;
  630. {
  631.     if (str == &str_undef)
  632.     return;
  633.     if (str->str_state == SS_INCR)
  634.     Str_Grow(str,0);    /* just force copy down */
  635.     if (nstr->str_state == SS_INCR)
  636.     Str_Grow(nstr,0);
  637.     if (str->str_ptr)
  638.     Safefree(str->str_ptr);
  639.     str->str_ptr = nstr->str_ptr;
  640.     str->str_len = nstr->str_len;
  641.     str->str_cur = nstr->str_cur;
  642.     str->str_pok = nstr->str_pok;
  643.     str->str_nok = nstr->str_nok;
  644. #ifdef STRUCTCOPY
  645.     str->str_u = nstr->str_u;
  646. #else
  647.     str->str_u.str_nval = nstr->str_u.str_nval;
  648. #endif
  649. #ifdef TAINT
  650.     str->str_tainted = nstr->str_tainted;
  651. #endif
  652.     if (nstr->str_magic)
  653.     str_free(nstr->str_magic);
  654.     Safefree(nstr);
  655. }
  656.  
  657.  
  658. void
  659. str_free(str)
  660. register STR *str;
  661. {
  662.     if (!str || str == &str_undef)
  663.     return;
  664.     if (str->str_state) {
  665.     if (str->str_state == SS_FREE)    /* already freed */
  666.         return;
  667.     if (str->str_state == SS_INCR && !(str->str_pok & 2)) {
  668.         str->str_ptr -= str->str_u.str_useful;
  669.         str->str_len += str->str_u.str_useful;
  670.     }
  671.     }
  672.     if (str->str_magic)
  673.     str_free(str->str_magic);
  674.     str->str_magic = freestrroot;
  675. #ifdef LEAKTEST
  676.     if (str->str_len) {
  677.     Safefree(str->str_ptr);
  678.     str->str_ptr = Nullch;
  679.     }
  680.     if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
  681.     arg_free(str->str_u.str_args);
  682.     Safefree(str);
  683. #else /* LEAKTEST */
  684.     if (str->str_len) {
  685.     if (str->str_len > 127) {    /* next user not likely to want more */
  686.         Safefree(str->str_ptr);    /* so give it back to malloc */
  687.         str->str_ptr = Nullch;
  688.         str->str_len = 0;
  689.     }
  690.     else
  691.         str->str_ptr[0] = '\0';
  692.     }
  693.     if ((str->str_pok & SP_INTRP) && str->str_u.str_args)
  694.     arg_free(str->str_u.str_args);
  695.     str->str_cur = 0;
  696.     str->str_nok = 0;
  697.     str->str_pok = 0;
  698.     str->str_state = SS_FREE;
  699. #ifdef TAINT
  700.     str->str_tainted = 0;
  701. #endif
  702.     freestrroot = str;
  703. #endif /* LEAKTEST */
  704. }
  705.  
  706.  
  707. STRLEN
  708. str_len(str)
  709. register STR *str;
  710. {
  711.     if (!str)
  712.     return 0;
  713.     if (!(str->str_pok))
  714.     (void)str_2ptr(str);
  715.     if (str->str_ptr)
  716.     return str->str_cur;
  717.     else
  718.     return 0;
  719. }
  720.  
  721.  
  722. str_eq(str1,str2)
  723. register STR *str1;
  724. register STR *str2;
  725. {
  726.     if (!str1 || str1 == &str_undef)
  727.     return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur);
  728.     if (!str2 || str2 == &str_undef)
  729.     return !str1->str_cur;
  730.  
  731.  
  732.     if (!str1->str_pok)
  733.     (void)str_2ptr(str1);
  734.     if (!str2->str_pok)
  735.     (void)str_2ptr(str2);
  736.  
  737.  
  738.     if (str1->str_cur != str2->str_cur)
  739.     return 0;
  740.  
  741.  
  742.     return !bcmp(str1->str_ptr, str2->str_ptr, str1->str_cur);
  743. }
  744.  
  745.  
  746. str_cmp(str1,str2)
  747. register STR *str1;
  748. register STR *str2;
  749. {
  750.     int retval;
  751.  
  752.  
  753.     if (!str1 || str1 == &str_undef)
  754.     return (str2 == Nullstr || str2 == &str_undef || !str2->str_cur)?0:-1;
  755.     if (!str2 || str2 == &str_undef)
  756.     return str1->str_cur != 0;
  757.  
  758.  
  759.     if (!str1->str_pok)
  760.     (void)str_2ptr(str1);
  761.     if (!str2->str_pok)
  762.     (void)str_2ptr(str2);
  763.  
  764.  
  765.     if (str1->str_cur < str2->str_cur) {
  766.     /*SUPPRESS 560*/
  767.     if (retval = memcmp(str1->str_ptr, str2->str_ptr, str1->str_cur))
  768.         return retval < 0 ? -1 : 1;
  769.     else
  770.         return -1;
  771.     }
  772.     /*SUPPRESS 560*/
  773.     else if (retval = memcmp(str1->str_ptr, str2->str_ptr, str2->str_cur))
  774.     return retval < 0 ? -1 : 1;
  775.     else if (str1->str_cur == str2->str_cur)
  776.     return 0;
  777.     else
  778.     return 1;
  779. }
  780.  
  781.  
  782. char *
  783. str_gets(str,fp,append)
  784. register STR *str;
  785. register FILE *fp;
  786. int append;
  787. {
  788.     register char *bp;        /* we're going to steal some values */
  789.     register int cnt;        /*  from the stdio struct and put EVERYTHING */
  790.     register STDCHAR *ptr;    /*   in the innermost loop into registers */
  791.     register int newline = rschar;/* (assuming >= 6 registers) */
  792.     int i;
  793.     STRLEN bpx;
  794.     int shortbuffered;
  795.  
  796.  
  797.     if (str == &str_undef)
  798.     return Nullch;
  799. #ifdef STDSTDIO        /* Here is some breathtakingly efficient cheating */
  800.     cnt = fp->_cnt;            /* get count into register */
  801.     str->str_nok = 0;            /* invalidate number */
  802.     str->str_pok = 1;            /* validate pointer */
  803.     if (str->str_len - append <= cnt + 1) { /* make sure we have the room */
  804.     if (cnt > 80 && str->str_len > append) {
  805.         shortbuffered = cnt - str->str_len + append + 1;
  806.         cnt -= shortbuffered;
  807.     }
  808.     else {
  809.         shortbuffered = 0;
  810.         STR_GROW(str, append+cnt+2);/* (remembering cnt can be -1) */
  811.     }
  812.     }
  813.     else
  814.     shortbuffered = 0;
  815.     bp = str->str_ptr + append;        /* move these two too to registers */
  816.     ptr = fp->_ptr;
  817.     for (;;) {
  818.       screamer:
  819.     while (--cnt >= 0) {            /* this */    /* eat */
  820.         if ((*bp++ = *ptr++) == newline)    /* really */    /* dust */
  821.         goto thats_all_folks;        /* screams */    /* sed :-) */
  822.     }
  823.     
  824.     if (shortbuffered) {            /* oh well, must extend */
  825.         cnt = shortbuffered;
  826.         shortbuffered = 0;
  827.         bpx = bp - str->str_ptr;    /* prepare for possible relocation */
  828.         str->str_cur = bpx;
  829.         STR_GROW(str, str->str_len + append + cnt + 2);
  830.         bp = str->str_ptr + bpx;    /* reconstitute our pointer */
  831.         continue;
  832.     }
  833.  
  834.  
  835.     fp->_cnt = cnt;            /* deregisterize cnt and ptr */
  836.     fp->_ptr = ptr;
  837.     i = _filbuf(fp);        /* get more characters */
  838.     cnt = fp->_cnt;
  839.     ptr = fp->_ptr;            /* reregisterize cnt and ptr */
  840.  
  841.  
  842.     bpx = bp - str->str_ptr;    /* prepare for possible relocation */
  843.     str->str_cur = bpx;
  844.     STR_GROW(str, bpx + cnt + 2);
  845.     bp = str->str_ptr + bpx;    /* reconstitute our pointer */
  846.  
  847.  
  848.     if (i == newline) {        /* all done for now? */
  849.         *bp++ = i;
  850.         goto thats_all_folks;
  851.     }
  852.     else if (i == EOF)        /* all done for ever? */
  853.         goto thats_really_all_folks;
  854.     *bp++ = i;            /* now go back to screaming loop */
  855.     }
  856.  
  857.  
  858. thats_all_folks:
  859.     if (rslen > 1 && (bp - str->str_ptr < rslen || bcmp(bp - rslen, rs, rslen)))
  860.     goto screamer;    /* go back to the fray */
  861. thats_really_all_folks:
  862.     if (shortbuffered)
  863.     cnt += shortbuffered;
  864.     fp->_cnt = cnt;            /* put these back or we're in trouble */
  865.     fp->_ptr = ptr;
  866.     *bp = '\0';
  867.     str->str_cur = bp - str->str_ptr;    /* set length */
  868.  
  869.  
  870. #else /* !STDSTDIO */    /* The big, slow, and stupid way */
  871.  
  872.  
  873.     {
  874.     static char buf[8192];
  875.     char * bpe = buf + sizeof(buf) - 3;
  876.  
  877.  
  878. screamer:
  879.     bp = buf;
  880.     while ((i = getc(fp)) != EOF && (*bp++ = i) != newline && bp < bpe) ;
  881.  
  882.  
  883.     *bp = '\0';
  884.     if (append)
  885.         str_cat(str, buf);
  886.     else
  887.         str_set(str, buf);
  888.     if (i != EOF            /* joy */
  889.         &&
  890.         (i != newline
  891.          ||
  892.          (rslen > 1
  893.           &&
  894.           (str->str_cur < rslen
  895.            ||
  896.            bcmp(str->str_ptr + str->str_cur - rslen, rs, rslen)
  897.           )
  898.          )
  899.         )
  900.        )
  901.     {
  902.         append = -1;
  903.         goto screamer;
  904.     }
  905.     }
  906.  
  907.  
  908. #endif /* STDSTDIO */
  909.  
  910.  
  911.     return str->str_cur - append ? str->str_ptr : Nullch;
  912. }
  913.  
  914.  
  915. ARG *
  916. parselist(str)
  917. STR *str;
  918. {
  919.     register CMD *cmd;
  920.     register ARG *arg;
  921.     CMD *oldcurcmd = curcmd;
  922.     int oldperldb = perldb;
  923.     int retval;
  924.  
  925.  
  926.     perldb = 0;
  927.     str_sset(linestr,str);
  928.     in_eval++;
  929.     oldoldbufptr = oldbufptr = bufptr = str_get(linestr);
  930.     bufend = bufptr + linestr->str_cur;
  931.     if (++loop_ptr >= loop_max) {
  932.         loop_max += 128;
  933.         Renew(loop_stack, loop_max, struct loop);
  934.     }
  935.     loop_stack[loop_ptr].loop_label = "_EVAL_";
  936.     loop_stack[loop_ptr].loop_sp = 0;
  937. #ifdef DEBUGGING
  938.     if (debug & 4) {
  939.         deb("(Pushing label #%d _EVAL_)\n", loop_ptr);
  940.     }
  941. #endif
  942.     if (setjmp(loop_stack[loop_ptr].loop_env)) {
  943.     in_eval--;
  944.     loop_ptr--;
  945.     perldb = oldperldb;
  946.     fatal("%s\n",stab_val(stabent("@",TRUE))->str_ptr);
  947.     }
  948. #ifdef DEBUGGING
  949.     if (debug & 4) {
  950.     char *tmps = loop_stack[loop_ptr].loop_label;
  951.     deb("(Popping label #%d %s)\n",loop_ptr,
  952.         tmps ? tmps : "" );
  953.     }
  954. #endif
  955.     loop_ptr--;
  956.     error_count = 0;
  957.     curcmd = &compiling;
  958.     curcmd->c_line = oldcurcmd->c_line;
  959.     retval = yyparse();
  960.     curcmd = oldcurcmd;
  961.     perldb = oldperldb;
  962.     in_eval--;
  963.     if (retval || error_count)
  964.     fatal("Invalid component in string or format");
  965.     cmd = eval_root;
  966.     arg = cmd->c_expr;
  967.     if (cmd->c_type != C_EXPR || cmd->c_next || arg->arg_type != O_LIST)
  968.     fatal("panic: error in parselist %d %x %d", cmd->c_type,
  969.       cmd->c_next, arg ? arg->arg_type : -1);
  970.     Safefree(cmd);
  971.     eval_root = Nullcmd;
  972.     return arg;
  973. }
  974.  
  975.  
  976. void
  977. intrpcompile(src)
  978. STR *src;
  979. {
  980.     register char *s = str_get(src);
  981.     register char *send = s + src->str_cur;
  982.     register STR *str;
  983.     register char *t;
  984.     STR *toparse;
  985.     STRLEN len;
  986.     register int brackets;
  987.     register char *d;
  988.     STAB *stab;
  989.     char *checkpoint;
  990.     int sawcase = 0;
  991.  
  992.  
  993.     toparse = Str_new(76,0);
  994.     str = Str_new(77,0);
  995.  
  996.  
  997.     str_nset(str,"",0);
  998.     str_nset(toparse,"",0);
  999.     t = s;
  1000.     while (s < send) {
  1001.     if (*s == '\\' && s[1] && index("$@[{\\]}lLuUE",s[1])) {
  1002.         str_ncat(str, t, s - t);
  1003.         ++s;
  1004.         if (isALPHA(*s)) {
  1005.         str_ncat(str, "$c", 2);
  1006.         sawcase = (*s != 'E');
  1007.         }
  1008.         else {
  1009.         if (*nointrp) {        /* in a regular expression */
  1010.             if (*s == '@')    /* always strip \@ */ /*SUPPRESS 530*/
  1011.             ;
  1012.             else if (*s == '$') {
  1013.             if (s+1 >= send || index(nointrp, s[1]))
  1014.                 str_ncat(str,s-1,1); /* only strip \$ for vars */
  1015.             }
  1016.             else        /* don't strip \\, \[, \{ etc. */
  1017.             str_ncat(str,s-1,1);
  1018.         }
  1019.         str_ncat(str, "$b", 2);
  1020.         }
  1021.         str_ncat(str, s, 1);
  1022.         ++s;
  1023.         t = s;
  1024.     }
  1025.     else if (*s == '$' && s+1 < send && *nointrp && index(nointrp,s[1])) {
  1026.         str_ncat(str, t, s - t);
  1027.         str_ncat(str, "$b", 2);
  1028.         str_ncat(str, s, 2);
  1029.         s += 2;
  1030.         t = s;
  1031.     }
  1032.     else if ((*s == '@' || *s == '$') && s+1 < send) {
  1033.         str_ncat(str,t,s-t);
  1034.         t = s;
  1035.         if (*s == '$' && s[1] == '#' && (isALPHA(s[2]) || s[2] == '_'))
  1036.         s++;
  1037.         s = scanident(s,send,tokenbuf);
  1038.         if (*t == '@' &&
  1039.           (!(stab = stabent(tokenbuf,FALSE)) ||
  1040.          (*s == '{' ? !stab_xhash(stab) : !stab_xarray(stab)) )) {
  1041.         str_ncat(str,"@",1);
  1042.         s = ++t;
  1043.         continue;    /* grandfather @ from old scripts */
  1044.         }
  1045.         str_ncat(str,"$a",2);
  1046.         str_ncat(toparse,",",1);
  1047.         if (t[1] != '{' && (*s == '['  || *s == '{' /* }} */ ) &&
  1048.           (stab = stabent(tokenbuf,FALSE)) &&
  1049.           ((*s == '[') ? (stab_xarray(stab) != 0) : (stab_xhash(stab) != 0)) ) {
  1050.         brackets = 0;
  1051.         checkpoint = s;
  1052.         do {
  1053.             switch (*s) {
  1054.             case '[':
  1055.             if (s[-1] != '$')
  1056.                 brackets++;
  1057.             break;
  1058.             case '{':
  1059.             brackets++;
  1060.             break;
  1061.             case ']':
  1062.             if (s[-1] != '$')
  1063.                 brackets--;
  1064.             break;
  1065.             case '}':
  1066.             brackets--;
  1067.             break;
  1068.             case '\'':
  1069.             case '"':
  1070.             if (s[-1] != '$') {
  1071.                 /*SUPPRESS 68*/
  1072.                 s = cpytill(tokenbuf,s+1,send,*s,&len);
  1073.                 if (s >= send)
  1074.                 fatal("Unterminated string");
  1075.             }
  1076.             break;
  1077.             }
  1078.             s++;
  1079.         } while (brackets > 0 && s < send);
  1080.         if (s > send)
  1081.             fatal("Unmatched brackets in string");
  1082.         if (*nointrp) {        /* we're in a regular expression */
  1083.             d = checkpoint;
  1084.             if (*d == '{' && s[-1] == '}') {    /* maybe {n,m} */
  1085.             ++d;
  1086.             if (isDIGIT(*d)) {    /* matches /^{\d,?\d*}$/ */
  1087.                 if (*++d == ',')
  1088.                 ++d;
  1089.                 while (isDIGIT(*d))
  1090.                 d++;
  1091.                 if (d == s - 1)
  1092.                 s = checkpoint;        /* Is {n,m}! Backoff! */
  1093.             }
  1094.             }
  1095.             else if (*d == '[' && s[-1] == ']') { /* char class? */
  1096.             int weight = 2;        /* let's weigh the evidence */
  1097.             char seen[256];
  1098.             unsigned char un_char = 0, last_un_char;
  1099.  
  1100.  
  1101.             Zero(seen,256,char);
  1102.             *--s = '\0';
  1103.             if (d[1] == '^')
  1104.                 weight += 150;
  1105.             else if (d[1] == '$')
  1106.                 weight -= 3;
  1107.             if (isDIGIT(d[1])) {
  1108.                 if (d[2]) {
  1109.                 if (isDIGIT(d[2]) && !d[3])
  1110.                     weight -= 10;
  1111.                 }
  1112.                 else
  1113.                 weight -= 100;
  1114.             }
  1115.             for (d++; d < s; d++) {
  1116.                 last_un_char = un_char;
  1117.                 un_char = (unsigned char)*d;
  1118.                 switch (*d) {
  1119.                 case '&':
  1120.                 case '$':
  1121.                 weight -= seen[un_char] * 10;
  1122.                 if (isALNUM(d[1])) {
  1123.                     d = scanident(d,s,tokenbuf);
  1124.                     if (stabent(tokenbuf,FALSE))
  1125.                     weight -= 100;
  1126.                     else
  1127.                     weight -= 10;
  1128.                 }
  1129.                 else if (*d == '$' && d[1] &&
  1130.                   index("[#!%*<>()-=",d[1])) {
  1131.                     if (!d[2] || /*{*/ index("])} =",d[2]))
  1132.                     weight -= 10;
  1133.                     else
  1134.                     weight -= 1;
  1135.                 }
  1136.                 break;
  1137.                 case '\\':
  1138.                 un_char = 254;
  1139.                 if (d[1]) {
  1140.                     if (index("wds",d[1]))
  1141.                     weight += 100;
  1142.                     else if (seen['\''] || seen['"'])
  1143.                     weight += 1;
  1144.                     else if (index("rnftb",d[1]))
  1145.                     weight += 40;
  1146.                     else if (isDIGIT(d[1])) {
  1147.                     weight += 40;
  1148.                     while (d[1] && isDIGIT(d[1]))
  1149.                         d++;
  1150.                     }
  1151.                 }
  1152.                 else
  1153.                     weight += 100;
  1154.                 break;
  1155.                 case '-':
  1156.                 if (last_un_char < (unsigned char) d[1]
  1157.                   || d[1] == '\\') {
  1158.                     if (index("aA01! ",last_un_char))
  1159.                     weight += 30;
  1160.                     if (index("zZ79~",d[1]))
  1161.                     weight += 30;
  1162.                 }
  1163.                 else
  1164.                     weight -= 1;
  1165.                 default:
  1166.                 if (isALPHA(*d) && d[1] && isALPHA(d[1])) {
  1167.                     bufptr = d;
  1168.                     if (yylex() != WORD)
  1169.                     weight -= 150;
  1170.                     d = bufptr;
  1171.                 }
  1172.                 if (un_char == last_un_char + 1)
  1173.                     weight += 5;
  1174.                 weight -= seen[un_char];
  1175.                 break;
  1176.                 }
  1177.                 seen[un_char]++;
  1178.             }
  1179. #ifdef DEBUGGING
  1180.             if (debug & 512)
  1181.                 fprintf(stderr,"[%s] weight %d\n",
  1182.                   checkpoint+1,weight);
  1183. #endif
  1184.             *s++ = ']';
  1185.             if (weight >= 0)    /* probably a character class */
  1186.                 s = checkpoint;
  1187.             }
  1188.         }
  1189.         }
  1190.         if (*t == '@')
  1191.         str_ncat(toparse, "join($\",", 8);
  1192.         if (t[1] == '{' && s[-1] == '}') {
  1193.         str_ncat(toparse, t, 1);
  1194.         str_ncat(toparse, t+2, s - t - 3);
  1195.         }
  1196.         else
  1197.         str_ncat(toparse, t, s - t);
  1198.         if (*t == '@')
  1199.         str_ncat(toparse, ")", 1);
  1200.         t = s;
  1201.     }
  1202.     else
  1203.         s++;
  1204.     }
  1205.     str_ncat(str,t,s-t);
  1206.     if (sawcase)
  1207.     str_ncat(str, "$cE", 3);
  1208.     if (toparse->str_ptr && *toparse->str_ptr == ',') {
  1209.     *toparse->str_ptr = '(';
  1210.     str_ncat(toparse,",$$);",5);
  1211.     str->str_u.str_args = parselist(toparse);
  1212.     str->str_u.str_args->arg_len--;        /* ignore $$ reference */
  1213.     }
  1214.     else
  1215.     str->str_u.str_args = Nullarg;
  1216.     str_free(toparse);
  1217.     str->str_pok |= SP_INTRP;
  1218.     str->str_nok = 0;
  1219.     str_replace(src,str);
  1220. }
  1221.  
  1222.  
  1223. STR *
  1224. interp(str,src,sp)
  1225. register STR *str;
  1226. STR *src;
  1227. int sp;
  1228. {
  1229.     register char *s;
  1230.     register char *t;
  1231.     register char *send;
  1232.     register STR **elem;
  1233.     int docase = 0;
  1234.     int l = 0;
  1235.     int u = 0;
  1236.     int L = 0;
  1237.     int U = 0;
  1238.  
  1239.  
  1240.     if (str == &str_undef)
  1241.     return Nullstr;
  1242.     if (!(src->str_pok & SP_INTRP)) {
  1243.     int oldsave = savestack->ary_fill;
  1244.  
  1245.  
  1246.     (void)savehptr(&curstash);
  1247.     curstash = curcmd->c_stash;    /* so stabent knows right package */
  1248.     intrpcompile(src);
  1249.     restorelist(oldsave);
  1250.     }
  1251.     s = src->str_ptr;        /* assumed valid since str_pok set */
  1252.     t = s;
  1253.     send = s + src->str_cur;
  1254.  
  1255.  
  1256.     if (src->str_u.str_args) {
  1257.     (void)eval(src->str_u.str_args,G_ARRAY,sp);
  1258.     /* Assuming we have correct # of args */
  1259.     elem = stack->ary_array + sp;
  1260.     }
  1261.  
  1262.  
  1263.     str_nset(str,"",0);
  1264.     while (s < send) {
  1265.     if (*s == '$' && s+1 < send) {
  1266.         if (s-t > 0)
  1267.         str_ncat(str,t,s-t);
  1268.         switch(*++s) {
  1269.         default:
  1270.         fatal("panic: unknown interp cookie\n");
  1271.         break;
  1272.         case 'a':
  1273.         str_scat(str,*++elem);
  1274.         break;
  1275.         case 'b':
  1276.         str_ncat(str,++s,1);
  1277.         break;
  1278.         case 'c':
  1279.         if (docase && str->str_cur >= docase) {
  1280.             char *b = str->str_ptr + --docase;
  1281.  
  1282.  
  1283.             if (L)
  1284.             lcase(b, str->str_ptr + str->str_cur);
  1285.             else if (U)
  1286.             ucase(b, str->str_ptr + str->str_cur);
  1287.  
  1288.  
  1289.             if (u)    /* note that l & u are independent of L & U */
  1290.             ucase(b, b+1);
  1291.             else if (l)
  1292.             lcase(b, b+1);
  1293.             l = u = 0;
  1294.         }
  1295.         docase = str->str_cur + 1;
  1296.         switch (*++s) {
  1297.         case 'u':
  1298.             u = 1;
  1299.             l = 0;
  1300.             break;
  1301.         case 'U':
  1302.             U = 1;
  1303.             L = 0;
  1304.             break;
  1305.         case 'l':
  1306.             l = 1;
  1307.             u = 0;
  1308.             break;
  1309.         case 'L':
  1310.             L = 1;
  1311.             U = 0;
  1312.             break;
  1313.         case 'E':
  1314.             docase = L = U = l = u = 0;
  1315.             break;
  1316.         }
  1317.         break;
  1318.         }
  1319.         t = ++s;
  1320.     }
  1321.     else
  1322.         s++;
  1323.     }
  1324.     if (s-t > 0)
  1325.     str_ncat(str,t,s-t);
  1326.     return str;
  1327. }
  1328.  
  1329.  
  1330. ucase(s,send)
  1331. register char *s;
  1332. register char *send;
  1333. {
  1334.     while (s < send) {
  1335.     if (isLOWER(*s))
  1336.         *s = toupper(*s);
  1337.     s++;
  1338.     }
  1339. }
  1340.  
  1341.  
  1342. lcase(s,send)
  1343. register char *s;
  1344. register char *send;
  1345. {
  1346.     while (s < send) {
  1347.     if (isUPPER(*s))
  1348.         *s = tolower(*s);
  1349.     s++;
  1350.     }
  1351. }
  1352.  
  1353.  
  1354. void
  1355. str_inc(str)
  1356. register STR *str;
  1357. {
  1358.     register char *d;
  1359.  
  1360.  
  1361.     if (!str || str == &str_undef)
  1362.     return;
  1363.     if (str->str_nok) {
  1364.     str->str_u.str_nval += 1.0;
  1365.     str->str_pok = 0;
  1366.     return;
  1367.     }
  1368.     if (!str->str_pok || !*str->str_ptr) {
  1369.     str->str_u.str_nval = 1.0;
  1370.     str->str_nok = 1;
  1371.     str->str_pok = 0;
  1372.     return;
  1373.     }
  1374.     d = str->str_ptr;
  1375.     while (isALPHA(*d)) d++;
  1376.     while (isDIGIT(*d)) d++;
  1377.     if (*d) {
  1378.         str_numset(str,atof(str->str_ptr) + 1.0);  /* punt */
  1379.     return;
  1380.     }
  1381.     d--;
  1382.     while (d >= str->str_ptr) {
  1383.     if (isDIGIT(*d)) {
  1384.         if (++*d <= '9')
  1385.         return;
  1386.         *(d--) = '0';
  1387.     }
  1388.     else {
  1389.         ++*d;
  1390.         if (isALPHA(*d))
  1391.         return;
  1392.         *(d--) -= 'z' - 'a' + 1;
  1393.     }
  1394.     }
  1395.     /* oh,oh, the number grew */
  1396.     STR_GROW(str, str->str_cur + 2);
  1397.     str->str_cur++;
  1398.     for (d = str->str_ptr + str->str_cur; d > str->str_ptr; d--)
  1399.     *d = d[-1];
  1400.     if (isDIGIT(d[1]))
  1401.     *d = '1';
  1402.     else
  1403.     *d = d[1];
  1404. }
  1405.  
  1406.  
  1407. void
  1408. str_dec(str)
  1409. register STR *str;
  1410. {
  1411.     if (!str || str == &str_undef)
  1412.     return;
  1413.     if (str->str_nok) {
  1414.     str->str_u.str_nval -= 1.0;
  1415.     str->str_pok = 0;
  1416.     return;
  1417.     }
  1418.     if (!str->str_pok) {
  1419.     str->str_u.str_nval = -1.0;
  1420.     str->str_nok = 1;
  1421.     return;
  1422.     }
  1423.     str_numset(str,atof(str->str_ptr) - 1.0);
  1424. }
  1425.  
  1426.  
  1427. /* Make a string that will exist for the duration of the expression
  1428.  * evaluation.  Actually, it may have to last longer than that, but
  1429.  * hopefully cmd_exec won't free it until it has been assigned to a
  1430.  * permanent location. */
  1431.  
  1432.  
  1433. static long tmps_size = -1;
  1434.  
  1435.  
  1436. STR *
  1437. str_mortal(oldstr)
  1438. STR *oldstr;
  1439. {
  1440.     register STR *str = Str_new(78,0);
  1441.  
  1442.  
  1443.     str_sset(str,oldstr);
  1444.     if (++tmps_max > tmps_size) {
  1445.     tmps_size = tmps_max;
  1446.     if (!(tmps_size & 127)) {
  1447.         if (tmps_size)
  1448.         Renew(tmps_list, tmps_size + 128, STR*);
  1449.         else
  1450.         New(702,tmps_list, 128, STR*);
  1451.     }
  1452.     }
  1453.     tmps_list[tmps_max] = str;
  1454.     if (str->str_pok)
  1455.     str->str_pok |= SP_TEMP;
  1456.     return str;
  1457. }
  1458.  
  1459.  
  1460. /* same thing without the copying */
  1461.  
  1462.  
  1463. STR *
  1464. str_2mortal(str)
  1465. register STR *str;
  1466. {
  1467.     if (str == &str_undef)
  1468.     return str;
  1469.     if (++tmps_max > tmps_size) {
  1470.     tmps_size = tmps_max;
  1471.     if (!(tmps_size & 127)) {
  1472.         if (tmps_size)
  1473.         Renew(tmps_list, tmps_size + 128, STR*);
  1474.         else
  1475.         New(704,tmps_list, 128, STR*);
  1476.     }
  1477.     }
  1478.     tmps_list[tmps_max] = str;
  1479.     if (str->str_pok)
  1480.     str->str_pok |= SP_TEMP;
  1481.     return str;
  1482. }
  1483.  
  1484.  
  1485. STR *
  1486. str_make(s,len)
  1487. char *s;
  1488. STRLEN len;
  1489. {
  1490.     register STR *str = Str_new(79,0);
  1491.  
  1492.  
  1493.     if (!len)
  1494.     len = strlen(s);
  1495.     str_nset(str,s,len);
  1496.     return str;
  1497. }
  1498.  
  1499.  
  1500. STR *
  1501. str_nmake(n)
  1502. double n;
  1503. {
  1504.     register STR *str = Str_new(80,0);
  1505.  
  1506.  
  1507.     str_numset(str,n);
  1508.     return str;
  1509. }
  1510.  
  1511.  
  1512. /* make an exact duplicate of old */
  1513.  
  1514.  
  1515. STR *
  1516. str_smake(old)
  1517. register STR *old;
  1518. {
  1519.     register STR *new = Str_new(81,0);
  1520.  
  1521.  
  1522.     if (!old)
  1523.     return Nullstr;
  1524.     if (old->str_state == SS_FREE) {
  1525.     warn("semi-panic: attempt to dup freed string");
  1526.     return Nullstr;
  1527.     }
  1528.     if (old->str_state == SS_INCR && !(old->str_pok & 2))
  1529.     Str_Grow(old,0);
  1530.     if (new->str_ptr)
  1531.     Safefree(new->str_ptr);
  1532.     Copy(old,new,1,STR);
  1533.     if (old->str_ptr) {
  1534.     new->str_ptr = nsavestr(old->str_ptr,old->str_len);
  1535.     new->str_pok &= ~SP_TEMP;
  1536.     }
  1537.     return new;
  1538. }
  1539.  
  1540.  
  1541. str_reset(s,stash)
  1542. register char *s;
  1543. HASH *stash;
  1544. {
  1545.     register HENT *entry;
  1546.     register STAB *stab;
  1547.     register STR *str;
  1548.     register int i;
  1549.     register SPAT *spat;
  1550.     register int max;
  1551.  
  1552.  
  1553.     if (!*s) {        /* reset ?? searches */
  1554.     for (spat = stash->tbl_spatroot;
  1555.       spat != Nullspat;
  1556.       spat = spat->spat_next) {
  1557.         spat->spat_flags &= ~SPAT_USED;
  1558.     }
  1559.     return;
  1560.     }
  1561.  
  1562.  
  1563.     /* reset variables */
  1564.  
  1565.  
  1566.     if (!stash->tbl_array)
  1567.     return;
  1568.     while (*s) {
  1569.     i = *s;
  1570.     if (s[1] == '-') {
  1571.         s += 2;
  1572.     }
  1573.     max = *s++;
  1574.     for ( ; i <= max; i++) {
  1575.         for (entry = stash->tbl_array[i];
  1576.           entry;
  1577.           entry = entry->hent_next) {
  1578.         stab = (STAB*)entry->hent_val;
  1579.         str = stab_val(stab);
  1580.         str->str_cur = 0;
  1581.         str->str_nok = 0;
  1582. #ifdef TAINT
  1583.         str->str_tainted = tainted;
  1584. #endif
  1585.         if (str->str_ptr != Nullch)
  1586.             str->str_ptr[0] = '\0';
  1587.         if (stab_xarray(stab)) {
  1588.             aclear(stab_xarray(stab));
  1589.         }
  1590.         if (stab_xhash(stab)) {
  1591.             hclear(stab_xhash(stab), FALSE);
  1592.             if (stab == envstab)
  1593.             environ[0] = Nullch;
  1594.         }
  1595.         }
  1596.     }
  1597.     }
  1598. }
  1599.  
  1600.  
  1601. #ifdef TAINT
  1602. taintproper(s)
  1603. char *s;
  1604. {
  1605. #ifdef DEBUGGING
  1606.     if (debug & 2048)
  1607.     fprintf(stderr,"%s %d %d %d\n",s,tainted,uid, euid);
  1608. #endif
  1609.     if (tainted && (!euid || euid != uid || egid != gid)) {
  1610.     if (!unsafe)
  1611.         fatal("%s", s);
  1612.     else if (dowarn)
  1613.         warn("%s", s);
  1614.     }
  1615. }
  1616.  
  1617.  
  1618. taintenv()
  1619. {
  1620.     register STR *envstr;
  1621.  
  1622.  
  1623.     envstr = hfetch(stab_hash(envstab),"PATH",4,FALSE);
  1624.     if (envstr == &str_undef || envstr->str_tainted) {
  1625.     tainted = 1;
  1626.     if (envstr->str_tainted == 2)
  1627.         taintproper("Insecure directory in PATH");
  1628.     else
  1629.         taintproper("Insecure PATH");
  1630.     }
  1631.     envstr = hfetch(stab_hash(envstab),"IFS",3,FALSE);
  1632.     if (envstr != &str_undef && envstr->str_tainted) {
  1633.     tainted = 1;
  1634.     taintproper("Insecure IFS");
  1635.     }
  1636. }
  1637. #endif /* TAINT */
  1638.